#include <stdio.h>
/*
 * 只有在两种场合下，数组名并不用指针常量来表示：
 * 当数组名作为sizeof或单目操作符&的操作数时。
 * sizeof返回整个数组的长度，而不是指向数组指针的长度
 *
 * 下标检查在c中是一项很困难的任务, 所涉及的开销很大
 *
 * 声明一个数组时，编译器将根据声明所指定的元素数量为数组保留内存空间，
 * 然后在创建数组名，它的值是一个常量，指向这段内存空间的起始地址。
 * 声明一个指针变量时，编译器只为指针本身保留内存空间，它并不为任何
 * 整形值分配内存空间。而且，指针变量并未初始化为指向任何现有的内存空间，
 * 如果它是一个自动变量，它甚至根本不会被初始化。
 *
 * char     message1[] = "hello";
 * char     *message2 = "hello";
 * 前者初始化一个字符数组的元素，后者则是一个真正的字符串常量。这个指针变量
 * 被初始化为指向这个字符串常量的存储位置
 *
 */

//void fun(int *a)
//函数原型中的一维数组形参无需写明元素数目，是因为函数并不为数组参数分配内存空间。
//形参只是一个指针，它指向的是已经在其他地方分配好的内存空间
void fun(int a[])
{
    *a = 5;
}

int main()
{
    int a[10], *ap;
    int i, j;

    for ( i = 0; i < 10; i++ )
        a[i] = i+1;
    for ( i = 0; i < 10; i++ )
        printf("%d, ", a[i]);
    printf("\n");

    printf("a =     %ld\n", a);
    printf("&a =    %ld\n", &a);
    printf("sizeof(a) =     %ld\n", sizeof(a));
    printf("sizeof(a[0]) =  %ld\n", sizeof(a[0]));
    printf("sizeof(a[8]) =  %ld\n", sizeof(a[8]));
    printf("&a[7] = %ld\n", &a[7]);
    printf("*a+6 =      %d\n", *a+6);
    printf("*(a+6) =    %d\n", *(a+6));

    /* 2[a] <=====> a[2]
     * 对编译器来说，这两种形式并无差别
     * 这个诡异的技巧之所以可行，缘于c实现下标的方法
     * 但这会大大影响程序的可读性
     */
    printf("6[a] =      %d\n", 6[a]);

    /*
     * 指针与下标的效率问题
     */
    //1、为了对下标表达式求值，编译器在程序中插入指令，取得a的值，并把它与整形的长度相乘
    //这个乘法需要花费一定的时间和空间
    for ( i = 0; i < 10; i++ )
        a[i] = 0;
    //2、在这里，乘法运算出现在for语句的调整部分。
    //这个值必须与整形的长度相乘，然后再与指针相加。
    //但这里存在一个重要差别：循环每次执行时，执行乘法运算的都是两个相同的数，结果，这个乘法只在编译时
    //执行一次，在运行的时候并不执行乘法运算，因而比1更有效率
    for ( ap = a; ap < a + 10; ap++ )
        *ap = 0;

    fun(a);
    for ( i = 0; i < 10; i++ )
        printf("%d, ", a[i]);
    printf("\n");

    

    return 0;
}
